package com.example.springboottest.example.mapnew;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Objects;

public class MapTest {
    public static void main(String[] args) {
        MapTest test = new MapTest();
//        test.computeIfAbsent();
        test.computeIfPresent();
    }

    public void foreach() {
        Map<String, Integer> ageOfFriends = new HashMap<>();
        //一直以来，遍历 Map 中的键和值都是非常笨拙的操作。实际上，你需要使用 Map.Entry<K,V>迭代器访问 Map 集合中的每一个元素：
        for (Map.Entry<String, Integer> entry : ageOfFriends.entrySet()) {
            String friend = entry.getKey();
            Integer age = entry.getValue();
            System.out.println(friend + " is " + age + " years old");
        }
        /*从 Java 8 开始，Map 接口开始支持 forEach 方法，该方法接受一个 BiConsumer，以 Map
        的键和值作为参数。使用 forEach 方法会让你的代码更简洁：*/
        ageOfFriends.forEach((friend, age) -> System.out.println(friend + " is " +
                age + " years old"));
    }

    public void getOrDefault() {
        /**
         * 你要查找的键在 Map 中并不存在时，就会收到一个空引用，你需要检查返回值以避免遭遇
         * NullPointerException。处理这种情况的一种通用做法是提供一个默认值。
         */
    }

    /**
     * 如果指定的键没有对应的值（没有该键或者该键对应的值是空），
     * 那么使用该键计算新的值，并将其添加到 Map 中
     */
    public void computeIfAbsent() {
        Map<String, Integer> moviesToCount = new HashMap<>();
        moviesToCount.computeIfAbsent("a", this::testComputeIfAbsent);
        System.out.println(moviesToCount.get("a"));
    }

    /**
     * 如果指定的键在 Map 中存在，就计算该键的新值，并将其添加
     * 到 Map 中
     */
    public void computeIfPresent() {
        Map<String, Integer> moviesToCount = new HashMap<>();
        moviesToCount.put("a", 88);
        moviesToCount.computeIfPresent("a", this::testComputeIfPresent);
        System.out.println(moviesToCount.get("a"));
    }

    private Integer testComputeIfAbsent(String key) {
        return 888;
    }

    private Integer testComputeIfPresent(String key, Integer value) {
        return value + 111;
    }

    /**
     * Map 中提供了两种新的方法来替换其内部映射项，分别是：
     *  replaceAll——通过 BiFunction 替换 Map 中每个项的值。该方法的工作模式类似于
     * 之前介绍过的 List 的 replaceAll 方法；
     *  Replace——如果键存在，就可以通过该方法替换 Map 中该键对应的值。它是对原有
     * replace 方法的重载，可以仅在原有键对应某个特定的值时才进行替换。
     */
    public void replaceAll() {
        Map<String, String> favouriteMovies = new HashMap<>();
        favouriteMovies.put("Raphael", "Star Wars");
        favouriteMovies.put("Olivia", "james bond");
        favouriteMovies.replaceAll((friend, movie) -> movie.toUpperCase());
        System.out.println(favouriteMovies);
    }

    /**
     * 我们介绍的替换模式仅支持单一 Map。如果需要合并两个 Map 并替换中间的值该怎么办呢？
     * 可以使用新的 merge 方法来完成该任务。
     */
    public void merge1() {
        //不好的方法
        Map<String, Integer> moviesToCount = new HashMap<>();
        String movieName = "JamesBond";
        Integer count = moviesToCount.get(movieName);
        if (count == null) {
            moviesToCount.put(movieName, 1);
        } else {
            moviesToCount.put(movieName, count + 1);
        }

        //采用新的方法，这段代码可以重写如下
        moviesToCount.merge(movieName, moviesToCount.getOrDefault(movieName, 0), (key, _count) -> _count + 1);
    }

    public void merge2() {
        Map<String, Integer> movies = new HashMap<>();
        movies.put("JamesBond", 20);
        movies.put("Matrix", 15);
        movies.put("Harry Potter", 5);
        Iterator<Map.Entry<String, Integer>> iterator =
                movies.entrySet().iterator();
        while (iterator.hasNext()) {
            Map.Entry<String, Integer> entry = iterator.next();
            if (entry.getValue() < 10) {
                iterator.remove();
            }
        }
        System.out.println(movies);

        //可以对 Map 的集合项使用 removeIf 方法，该方法接受一个谓词，依据谓词的结果删除元素
        movies.entrySet().removeIf(entry -> entry.getValue() < 10);
    }

    public void remove() {
        //不好的方法
        Map<String, String> favouriteMovies = new HashMap<>();
        String key = "Raphael";
        String value = "Jack Reacher 2";
        if (favouriteMovies.containsKey(key) &&
                Objects.equals(favouriteMovies.get(key), value)) {
            favouriteMovies.remove(key);
        } else {
        }

        // 要实现同样的功能，你只需要下面这一行代码。是不是简单直观很多？
        favouriteMovies.remove(key, value);
    }

}
